package cn.meng.base.listener;

import cn.hutool.core.date.DateTime;
import cn.meng.base.vo.BusinessException;
import cn.meng.base.vo.CanalDataVo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * Canal事件处理实现类
 * @author 万梦辉
 */
@Component
public class CanalListenerProcess extends CanalListenerBase{

    private final String INSERT = "INSERT";
    private final String DELETE = "DELETE";
    private final String UPDATE = "UPDATE";

    private final Logger log = LoggerFactory.getLogger(this.getClass());

    /**
     * 处理数据库触发新增日志
     */
    @Override
    public void insert(CanalDataVo data) {
        transitionProcess(data);
    }

    /**
     * 处理数据库触发删除日志
     */
    @Override
    public void delete(CanalDataVo data) {
        transitionProcess(data);
    }

    /**
     * 处理数据库触发更新日志
     */
    @Override
    public void update(CanalDataVo data) {
        transitionProcess(data);
    }

    private void transitionProcess(CanalDataVo data) {
        String databaseName = data.getDatabaseName();
        String tableName = data.getTableName();
        String type = data.getType();
        List<Map<String,Object>> newData = data.getNewData();
        List<String> pkNames = data.getPkNames();
        StringBuilder operationContent = new StringBuilder();
        operationContent.append("(在 ")
                .append(new DateTime().toString())
                .append(" 左右，对数据库： <")
                .append(databaseName).append(">  中的 <")
                .append(tableName)
                .append("> 表，进行了 <")
                .append(type)
                .append("> 操作)-->");
        //处理不同类型的消息内容
        if(INSERT.equals(type)) {
            operationContent.append("新增的数据为：{ ");
            String insertContent = dealInsertAndDeleteContent(newData);
            operationContent.append(insertContent).append(" }");
        }else if(DELETE.equals(type)) {
            operationContent.append("删除的数据为：{");
            String deleteContent = dealInsertAndDeleteContent(newData);
            operationContent.append(deleteContent).append(" }");
        }else if(UPDATE.equals(type)) {
            operationContent.append("修改的数据内容为：{ ");
            List<Map<String,Object>> oldValue = data.getOldValue();
            //获取所有update的字段
            List<String> alterFields = new ArrayList<>();
            for(String key : oldValue.get(0).keySet()) {
                if(null == key) {
                    continue;
                }
                alterFields.add(key);
            }
            String updateContent = dealUpdateContent(newData,oldValue,alterFields,pkNames);
            operationContent.append(updateContent).append(" }");
        }
        System.out.println(operationContent.toString());
    }

    /**
     * 对于新增、删除的消息内容特殊处理
     * @param newData ： 新增、删除 对应的内容
     * @return
     */
    private String dealInsertAndDeleteContent(List<Map<String,Object>> newData) {
        String result = "";
        for(Map<String,Object> data : newData) {
            String tempContent = "(";
            for(String key : data.keySet()) {
                if(tempContent.indexOf(",") != -1) {
                    tempContent = tempContent + ", ";
                }
                tempContent = tempContent + " " + key + ": " + data.get(key);
            }
            tempContent = tempContent + " )";
            result = result + tempContent + " ";
        }
        return result;
    }

    private String dealUpdateContent(List<Map<String,Object>> newData,List<Map<String,Object>> oldValue,List<String> alterFields,List<String> pkNames) {
        String result = "";
        String pkName = pkNames.get(0);
        for (int i = 0; i < newData.size(); i++) {
            String tempContent = " (";
            Map<String,Object> tempNewData = newData.get(i);
            Map<String,Object> tempOldValue = oldValue.get(i);
            tempContent = pkName + " : " + tempNewData.get(pkName) + tempContent;
            for(String field : alterFields) {
                if(tempContent.indexOf("{") != -1) {
                    tempContent = tempContent + ", ";
                }
                tempContent = tempContent + field + "={ oldValue: " + tempOldValue.get(field) + " ; newValue: " + tempNewData.get(field) + " }";
            }
            tempContent = tempContent + "),";
            result = result + tempContent;
        }
        StringBuffer tempDeal = new StringBuffer(result);
        result = tempDeal.replace(tempDeal.length() - 1 ,tempDeal.length(),"").toString();
        return result;
    }
}
